import json

from typing import Union
import datetime

from auto_dj_test.conf.MyLogger import MyLogger
from aweirunner import models
from rest_framework import serializers
from aweirunner.utils.parser import Parse
from django_celery_beat.models import PeriodicTask
from aweirunner.utils.tree import get_tree_relation_name
import croniter

logger = MyLogger(__name__)


class ProjectSerializer(serializers.ModelSerializer):
    """
    项目信息序列化
    """

    class Meta:
        model = models.Project
        fields = [
            "id",
            "name",
            "desc",
            "responsible",
            "creator",
            "updater",
            "update_time"
        ]


class APIRelatedCaseSerializer(serializers.Serializer):
    case_name = serializers.CharField(source="case.name")
    case_id = serializers.CharField(source="case.id")

    class Meta:
        fields = ["case_id", "case_name"]


class APISerializer(serializers.ModelSerializer):
    """
    接口信息序列化
    """

    body = serializers.SerializerMethodField()
    tag_name = serializers.CharField(source="get_tag_display")
    cases = serializers.SerializerMethodField()
    relation_name = serializers.SerializerMethodField()

    class Meta:
        model = models.API
        # fields = '__all__'
        fields = [
            "id",
            "name",
            "url",
            "method",
            "project",
            "relation",
            "body",
            "tag",
            "tag_name",
            "update_time",
            "delete",
            "creator",
            "updater",
            "cases",
            "relation_name",
        ]

    def get_body(self, obj):
        parse = Parse(eval(obj.body))
        parse.parse_http()
        return parse.testcase

    def get_cases(self, obj):
        cases = models.CaseStep.objects.filter(source_api_id=obj.id)
        case_id = APIRelatedCaseSerializer(many=True, instance=cases)
        return case_id.data

    def get_relation_name(self, obj):
        relation_obj = models.Relation.objects.get(project_id=obj.project_id, type=1)
        label = get_tree_relation_name(eval(relation_obj.tree), obj.relation)
        return label


class VisitSerializer(serializers.ModelSerializer):
    """
        访问统计序列化
        """

    class Meta:
        model = models.Visit
        fields = "__all__"


class AssertSerializer(serializers.Serializer):
    class Meta:
        models = models.API

    node = serializers.IntegerField(min_value=0, default="")
    # max_value=models.Project.objects.latest('id').id 会导致数据库迁移找不到project
    project = serializers.IntegerField(required=True, min_value=1)
    search = serializers.CharField(default="")
    creator = serializers.CharField(required=False, default="")
    tag = serializers.ChoiceField(choices=models.API.TAG, default="")
    # rigEnv = serializers.ChoiceField(choices=models.API.ENV_TYPE, default="")
    delete = serializers.ChoiceField(choices=(0, 1), default=0)
    onlyMe = serializers.BooleanField(default=False)


class ConfigSerializer(serializers.ModelSerializer):
    """
    配置信息序列化
    """

    body = serializers.SerializerMethodField()

    class Meta:
        model = models.Config
        fields = [
            "id",
            "base_url",
            "body",
            "name",
            "update_time",
            "is_default",
            "creator",
            "updater",
        ]
        depth = 1

    def get_body(self, obj):
        parse = Parse(eval(obj.body), level="config")
        parse.parse_http()
        return parse.testcase


class VariablesSerializer(serializers.ModelSerializer):
    """
    全局变量 序列化
    """

    key = serializers.CharField(allow_null=False, max_length=100, required=True)
    value = serializers.CharField(allow_null=False, max_length=1024)
    description = serializers.CharField(required=False, allow_blank=True)

    class Meta:
        model = models.Variables
        fields = "__all__"


class ReportSerializer(serializers.ModelSerializer):
    """
    报告信息序列化
    """
    # models对于设置了choice的字段，Django 将为每个字段生成一个以 get_字段名_display 命名的方法，用于获取字段的可读显示值。
    type = serializers.CharField(source="get_type_display")
    time = serializers.SerializerMethodField()
    stat = serializers.SerializerMethodField()
    platform = serializers.SerializerMethodField()
    success = serializers.SerializerMethodField()

    class Meta:
        model = models.Report
        fields = [
            "id",
            "name",
            "type",
            "time",
            "stat",
            "platform",
            "success",
            "creator",
            "updater",
        ]

    def get_time(self, obj):
        return json.loads(obj.summary)["time"]

    def get_stat(self, obj):
        return json.loads(obj.summary)["stat"]

    def get_platform(self, obj):
        return json.loads(obj.summary)["platform"]

    def get_success(self, obj):
        return json.loads(obj.summary)["success"]


def get_cron_next_execute_time(crontab_expr: str) -> int:
    now = datetime.datetime.now()
    try:
        cron = croniter.croniter(crontab_expr, now)
    except croniter.CroniterNotAlphaError:
        logger.warning(f"解析定时任务{crontab_expr=} 错误，返回0")
        # 解析定时任务错误，返回0
        return 0

    next_time: datetime.datetime = cron.get_next(datetime.datetime)
    return int(next_time.timestamp())


class PeriodicTaskSerializer(serializers.ModelSerializer):
    """
    定时任务信列表序列化
    """

    kwargs = serializers.SerializerMethodField()
    args = serializers.SerializerMethodField()
    last_run_at = serializers.SerializerMethodField()

    class Meta:
        model = PeriodicTask
        fields = [
            "id",
            "name",
            "args",
            "kwargs",
            "enabled",
            "date_changed",
            "enabled",
            "description",
            "total_run_count",
            "last_run_at",
        ]

    def get_kwargs(self, obj):
        kwargs = json.loads(obj.kwargs)
        if obj.enabled:
            kwargs["next_execute_time"] = get_cron_next_execute_time(kwargs["crontab"])
        # ci_project_ids = eval(kwargs.get('ci_project_ids', '[]'))
        # kwargs['ci_project_ids'] = ','.join(map(lambda x: str(x), ci_project_ids))
        kwargs["ci_project_ids"] = kwargs.get("ci_project_ids", "")
        kwargs["ci_env"] = kwargs.get("ci_env", "请选择")
        kwargs["config"] = kwargs.get("config", "请选择")
        # False:串行, True:并行
        kwargs["is_parallel"] = kwargs.get("is_parallel", False)
        return kwargs

    def get_args(self, obj):
        case_id_list = json.loads(obj.args)
        # 数据格式,list of dict : [{"id":case_id,"name":case_name}]
        return list(
            models.Case.objects.filter(pk__in=case_id_list).values("id", "name")
        )

    def get_last_run_at(self, obj) -> Union[str, int]:
        if obj.last_run_at:
            return int(obj.last_run_at.timestamp())
        return ""
